//
//  StardictDict.m
//  Words2
//
//  Created by Mathieu Tozer on 27/09/06.
//  Copyright 2006 __MyCompanyName__. All rights reserved.
//

#import "StardictDict.h"
#import <Foundation/Foundation.h>
#import "dict.h"
#import "WordsAppDelegate.h"

#pragma mark Drone Methods

// utf-8 character length ( http://en.wikipedia.org/wiki/UTF-8 )
int utf8LenByPrefixByte(char ch)
{
	unsigned char bt = (unsigned char)ch;
	if ((bt & (128+64+32+16+8)) == (128+64+32+16))
		return 4;
	if ((bt & (128+64+32+16)) == (128+64+32))
		return 3;
	if ((bt & (128+64+32)) == (128+64))
		return 2;
	if (!(bt & 128))
		return 1;
#ifdef VERBOSE
	fprintf(stderr,"utf8LenByPrefixByte: something wrong in UTF-8 things: 0x%X\n",
			bt);
#endif
	return 1;
}


@implementation StardictDict
-(NSString*)webColor:(NSColor*)aColor
{
	return [NSString stringWithFormat:@"#%02X%02X%02X",
		(unsigned)([aColor redComponent]*255.0+0.49),
		(unsigned)([aColor greenComponent]*255.0+0.49),
		(unsigned)([aColor blueComponent]*255.0+0.49)];
}

- (NSMutableString *)stringBlobOfDefinitions:(NSString *)word{
	//so my goal is to get this into my window.
	//this is what will need to be
	NSTextView * tempView = [[NSTextView alloc] init];
	[tempView setString:@""];
	NSTextStorage * tS = [tempView textStorage];
	


	// aText attibutes (default)
	NSDictionary *aText=[NSDictionary dictionaryWithObjects: 
		[NSArray arrayWithObjects:
			[[NSFontManager sharedFontManager]
				fontWithFamily:@"Helvetica"
						traits:NSUnboldFontMask
						weight:4 size:12],
			[NSColor blackColor],
			nil]
													forKeys:
		[NSArray arrayWithObjects:
			NSFontAttributeName,
			NSForegroundColorAttributeName,
			nil]
		]; 
	/* for 10.3.9 support
		NSLog(@"%@ %@",
			  NSCharacterEncodingDocumentOption,
			  NSTextSizeMultiplierDocumentOption);
	/* */
	// oEnc (encoding for HTML, font size)
	NSDictionary *oEnc=[NSDictionary dictionaryWithObjects: 
		[NSArray arrayWithObjects:
			[NSNumber numberWithInt:NSUTF8StringEncoding],
			[NSNumber numberWithFloat:
				MDICT_HTML_MIN_SCALE + 
				(MDICT_HTML_SCALE_LEN/MDICT_FONTSIZE_LEN)*(12-MDICT_MIN_FONTSIZE)],
			nil]
												   forKeys:
		[NSArray arrayWithObjects:
			@"CharacterEncoding",//NSCharacterEncodingDocumentOption,
			@"TextSizeMultiplier",//NSTextSizeMultiplierDocumentOption,
			nil]
		];
	// trancate and modify word
	NSMutableString * aWord = [NSMutableString 
												stringWithString:word];
	if ([aWord length] > MDICT_MAX_WORD_LEN)
		aWord = [NSMutableString stringWithString:
												[aWord substringToIndex:MDICT_MAX_WORD_LEN]];
	[aWord replaceOccurrencesOfString:@"\n" withString:@" " 
							  options:NSLiteralSearch range:NSMakeRange(0,[aWord length])];
	[aWord replaceOccurrencesOfString:@"\r" withString:@" " 
							  options:NSLiteralSearch range:NSMakeRange(0,[aWord length])];
	[aWord replaceOccurrencesOfString:@"\t" withString:@" " 
							  options:NSLiteralSearch 
								range:NSMakeRange(0,[aWord length])];
	
	while([aWord replaceOccurrencesOfString:@"  " withString:@" " 
									options:NSLiteralSearch range:NSMakeRange(0,[aWord length])]);
	while([aWord replaceOccurrencesOfString:@" " withString:@""
									options:NSLiteralSearch
									  range:NSMakeRange(0,[aWord length] ? 1 : 0)]);
	
	
	NSString *thisDictLocation = [self valueForKey:@"location"];
//	PIndexEntry something = newIndexEntry([thisDict UTF8String]);// create new index entry
	char *translated = getWord([thisDictLocation UTF8String],[aWord UTF8String],0);
	
	
	unsigned isHtml, forceBR, somethingTranslated = 0;
	if (translated){	
	//	NSString * dName = [NSString stringWithFormat:@"     %@  ( %@ )\n\n",
	//		aWord,[thisDictLocation UTF8String]];
		NSAttributedString *myNewLine=[[NSAttributedString alloc] 
				initWithString:@""];
		
		// parsing translated text for fine formating
		int newLine = 1;
		unsigned len = strlen(translated);
		int curPos = 0;
		char prevCh = 0;// prev single char
			char * eye = translated;
			char * already = NULL;
			enum {TRACE_STRING,TRACE_REM} mode = TRACE_STRING;
			while (curPos < len)
			 {
				if (translated[curPos] == '\n')
					newLine = 1;
				if (newLine)// look ahead for '\d+>'
				 {
					 unsigned from = curPos + (curPos ? 1 : 0 );
					 unsigned tracer = from;
					 while (tracer < len && isdigit(translated[tracer]))
						 tracer++;
					 if (from < tracer && translated[tracer] == '>')
						 translated[tracer] = '.';// change '>' after digits on new line to '.'
				 }
				if (!(translated[curPos] & 0x80))
				 {
					switch(mode)
					 {
						case TRACE_STRING:
							if (!isHtml && (!curPos || isspace(prevCh) ||
											strchr("([{<>}]).,;:/\\*!?`~'\"-=#$^@%&",prevCh)) 
								&& translated[curPos] == '_' && 
								!isspace(translated[curPos+1]))// '_' before string meaning comment
							 {
									mode = TRACE_REM;
									// output accumulated simple text
									translated[curPos] = 0;
									[myNewLine initWithString:[NSString stringWithUTF8String: eye] 
												   attributes: aText];

									NSLog(@"finita automate: simple text trigger: %s",eye);

									already = eye;
									eye = translated + curPos + 1;
									[tS appendAttributedString: myNewLine];
							 }
							break;
						case TRACE_REM:
							if (isspace(translated[curPos]) || !translated[curPos+1])
							 {
								mode = TRACE_STRING;
								// output accumulated comment text
								if (isHtml)
								 {
									[myNewLine initWithString:@" "];
									[tS appendAttributedString:myNewLine];
								 }
								translated[curPos] = 0;
								[myNewLine initWithString:[NSString stringWithUTF8String: eye]];

								NSLog(@"finita automate: comment text trigger: %s",eye);

								already = eye;
								eye = translated + curPos + 1;
								[tS appendAttributedString: myNewLine];
								if (*eye && !isspace(*eye))
								 {
									// force space appending after comment
									[myNewLine initWithString:@" "];
									[tS appendAttributedString: myNewLine];
								 }
							 }
							break;

						default:
							NSLog(@"finita automate: bad mode %i",mode);

					 }
					prevCh = translated[curPos];
				 }
				else
					prevCh = 0;
				curPos+= utf8LenByPrefixByte(translated[curPos]), newLine = 0;
			 }
			if (already != eye)// final string part
			 {
					 if (!isHtml)
						 [myNewLine initWithString:[NSString stringWithUTF8String: eye] 
										attributes: aText];
					 else
					  {
						 if (forceBR)
						  {
//							 NSMutableString * pre = [[[NSMutableString alloc] 
//														initWithUTF8String: eye] autorelease];
//							 [pre replaceOccurrencesOfString:@"\n" withString:@"<br>" 
//													 options:NSLiteralSearch range: NSMakeRange(0, [pre length])];
//							 [myNewLine initWithHTML:[[NSString stringWithFormat:
//								 @"<font color=%@>%@</font>",
//								 [self webColor:[NSColor]],pre] 
//											dataUsingEncoding:NSUTF8StringEncoding] 
//											 options:oEnc 
//								  documentAttributes:nil];
						  }else{
							 [myNewLine initWithHTML:[[NSString stringWithFormat:
								 @"<font color=%@>%@</font>",
								 [self webColor:[NSColor blackColor]],
								 [NSString stringWithUTF8String: eye]] 
													dataUsingEncoding:NSUTF8StringEncoding] 
											 options:oEnc
								  documentAttributes:nil];
					  }
				 }
			 }

			// NSLog(@"finita automate: last block: simple text trigger: %s",eye);
			
			 [tS appendAttributedString: myNewLine];
			 
			[myNewLine initWithString:[NSString stringWithString: @"\n\n"]];
			[tS appendAttributedString: myNewLine];
			[myNewLine release];				
			free(translated), translated = NULL;
			somethingTranslated = 1;
			
			if([[self valueForKey:@"encoding"] isEqualToString:@"UTF8"]){
				NSMutableString *blob = [[[NSMutableString alloc] initWithUTF8String:eye] autorelease];
				return blob;
			}
			NSLog(@"Stardict Encoding unsupported or not specified");
			//try other encodings here//
//			else{ //just try UTF8 anyway
//				
//			}
	}
	
	return nil;
}



- (NetworkConnectionMonitor *)networkConnectionMonitor{
	//noop
	return nil;
}
- (void)createConnectionMonitor{
	//noop
}

-(void)connect{
	//noop
}

-(bool)isRemote{
	return NO;
}

-(bool)isAvailable{
	return YES;
}

-(void)disconnect{
	//noop
}


-(NSString *)dictType{
	return @"StardictDict";
}


#pragma mark Archiving Support
- (void)encodeWithCoder:(NSCoder *)coder
{
    [super encodeWithCoder:coder];
	
	//remember, we want to end up with a nice NSData object that will be saved to the filesystem
	NSData *dictData = [NSData dataWithContentsOfFile:[self valueForKey:@"location"]];
	NSData *indexData = [NSData dataWithContentsOfFile:[self valueForKey:@"indexLocation"]];

	if(dictData && indexData){
		[coder encodeObject:dictData forKey:@"STARLocation"];
		[coder encodeObject:indexData forKey:@"STARIndexLocation"];
	}else{
		NSLog(@"dict data or index couldn't be encoded");
	}

    return;
}


//this is simply a method that is being run when something is being unarchived. it IS an instance method though... but of what?? A Dict Protocol Dict.
- (id)initWithCoder:(NSCoder *)coder
{
	//determine whether this dictionary already exists in this moc
	//set up the fetch request
	NSError *fetchError = nil; 
	NSEntityDescription *dictEntityDescription = [NSEntityDescription entityForName:@"Dictionary" inManagedObjectContext:[[NSApp delegate] managedObjectContext]]; 
	NSFetchRequest *dictRequest = [[[NSFetchRequest alloc] init] autorelease]; 
	[dictRequest setEntity:dictEntityDescription]; 
	
	NSPredicate *predicate = [NSPredicate predicateWithFormat:@"name LIKE[c] %@", [coder decodeObjectForKey:@"DName"]];
	[dictRequest setPredicate:predicate];
	//perform the request
	NSArray *existingDicts = [[[NSApp delegate] managedObjectContext] executeFetchRequest:dictRequest error:&fetchError]; 

//	//if there's not a dictionary of the same name already
	if([existingDicts count] == 0){
		
		StardictDict *dict = [NSEntityDescription insertNewObjectForEntityForName:@"StardictDict" 
																	 inManagedObjectContext:[[NSApp delegate] managedObjectContext]];
		
		//Generic dictionary attributes
		[dict setValue:[coder decodeObjectForKey:@"DCapabilities"] forKey:@"capabilities"];
		[dict setValue:[coder decodeObjectForKey:@"DName"] forKey:@"name"];
		[dict setValue:[coder decodeObjectForKey:@"DPivotLanguage"] forKey:@"pivotLanguage"];
		[dict setValue:[coder decodeObjectForKey:@"DtargetLanguages"] forKey:@"targetLanguages"];
		[dict setValue:[coder decodeObjectForKey:@"DIsRemote"] forKey:@"isRemote"];
		[dict setValue:[coder decodeObjectForKey:@"DDictionaryIconData"] forKey:@"dictionaryIconData"];	
		[dict setValue:[coder decodeObjectForKey:@"DLocalisedName"] forKey:@"localisedName"];
		[dict setValue:[coder decodeObjectForKey:@"DEncoding"] forKey:@"encoding"];
		
		
		NSData *dictData = [coder decodeObjectForKey:@"STARLocation"];
		NSData *indexData = [coder decodeObjectForKey:@"STARIndexLocation"];
		
		
		NSString * uniqueName = [[dict valueForKey:@"name"] stringByStandardizingPath];
		NSString * uniqueIndexName = [NSString stringWithFormat:@"%@.idx", uniqueName];
		NSString *homeDir = NSHomeDirectory();
		
	//	//contruct path to put the the .dict file and .idx file
		NSString *applicationSupportFolder = [[[NSFileManager defaultManager] findSystemFolderType:kApplicationSupportFolderType 
																						 forDomain:kOnSystemDisk] stringByStandardizingPath];
		//create a dictionaries folder if there isn't one available already
		NSString *dictionariesFolder = [NSString stringWithFormat:@"%@/%@/Words/Dictionaries/", homeDir, applicationSupportFolder];
		[[NSFileManager defaultManager] createDirectoryAtPath:[dictionariesFolder stringByStandardizingPath] attributes:nil];
		
		NSString *location = [[NSString stringWithFormat:@"%@/%@/Words/Dictionaries/%@.dict", homeDir, applicationSupportFolder, uniqueName] stringByStandardizingPath];
		NSString *indexLocation = [[NSString stringWithFormat:@"%@/%@/Words/Dictionaries/%@", homeDir, applicationSupportFolder, uniqueIndexName] stringByStandardizingPath];

		[dictData writeToFile:location atomically:YES];
		[indexData writeToFile:indexLocation atomically:YES];
		
		[dict setValue:[[NSString stringWithFormat:@"%@/%@/Words/Dictionaries/%@", homeDir, applicationSupportFolder, uniqueName] stringByStandardizingPath] forKey:@"location"]; //to use later
		[dict setValue:indexLocation forKey:@"indexLocation"];
		return self;
	}
	else{
		NSLog(@"You already have this dictionary! Perhaps two dictionaries have the same name... Oh well. Computer Said No");
		return nil;
	}
}


#pragma mark Keeping DictProtocolDictionary Under Wraps
-(NSString *)serverName{
	return @"NA";
}

-(NSString *)databaseName{
	return @"NA";
}

-(NSString *)username{
	return @"NA";
}
-(NSString *)password{
	return @"NA";
}
-(int)timeout{
	return 0;
}
@end
